home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / interapplication comm / folder watching / folder watcher fba / fbalists.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  9.5 KB  |  390 lines

  1. /*
  2.     File:        FBALists.c
  3.  
  4.     Contains:    
  5.  
  6.     Written by: Greg Sutton
  7.  
  8.     Copyright:    Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 7/21/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23.  
  24.  
  25. #include "FBALists.h"
  26.  
  27. #include "FBA.h"
  28. #include "FBATask.h"
  29.  
  30. #include <Memory.h>
  31. #include <Resources.h>
  32. #include <TextUtils.h>
  33. #include <ToolUtils.h>
  34.  
  35.     // Borrowed from MoreFiles 1.3.1
  36. #define hasCatSearch(volParms)        (((volParms).vMAttrib & (1L << bHasCatSearch)) != 0)
  37.  
  38.     // Prototypes
  39. static void                AddToList( ItemPtr* theHeadPtr, ItemPtr theItem );
  40. static void                FirstToLast( ItemPtr* theHeadPtr );
  41. static WatchVolumePtr    VolumeInList( short theVolRef );
  42. static OSErr            GetFullPath( FSSpec* theSpec, StringPtr thePath );
  43. static void                InsertAtBeginning( StringPtr sourceStr, StringPtr destStr );
  44. static OSErr            GetVolInfo( short theVolRef, GetVolParmsInfoBuffer* theBuffer );
  45.  
  46.     // Globals
  47. long                    gNumberFolders = 0;
  48. long                    gNumberVolumes = 0;
  49. WatchFolderPtr            gWatchFolderPtr = NULL;
  50. WatchVolumePtr            gWatchVolumePtr = NULL;
  51.  
  52. // Paths to the folder to be watched are stored in 'WFol' resources. This routine simply
  53. // reads through all of these resources adding them to the list of folders to watch.
  54.  
  55. Boolean    InitWatchFolders( void )
  56. {
  57.     short        count;
  58.     Handle        aHandle;
  59.     FSSpec        aSpec;
  60.     OSErr        err;
  61.     Boolean        result = true;
  62.  
  63.     count = Count1Resources( kWatchFolderResource );
  64.     
  65.     for ( ; count > 0; count-- )
  66.     {                            // Handle to a pascal string
  67.         aHandle = Get1IndResource( kWatchFolderResource, count );
  68.         
  69.         if (! aHandle)
  70.         {
  71.             result = false;        // If we fail on one we'll still try the rest
  72.             continue;
  73.         }
  74.         
  75.         HLock( aHandle );
  76.         err = FSMakeFSSpec( 0, 0, (StringPtr) *aHandle, &aSpec );
  77.         HUnlock( aHandle );
  78.         
  79.         if (noErr != err || ! AddFolder( &aSpec ))
  80.         {
  81.             RemoveResource( aHandle );    // Error in finding the folder or
  82.             result = false;                // no longer a file - get rid of it.
  83.         }
  84.         else
  85.             ReleaseResource( aHandle );
  86.     }
  87.     
  88.     return result;
  89. }
  90.  
  91.  
  92. // Check that the FSSpec is for a folder. If it is then create a WatchFolderPtr
  93. // that gets added to the front of the linked list.
  94.  
  95. Boolean    AddFolder( FSSpec* theSpec )
  96. {
  97.     WatchFolderPtr    tempPtr;
  98.     CInfoPBRec        pb;
  99.     OSErr            err;
  100.         
  101.     if ( FolderInList( theSpec ) )
  102.         return true;
  103.  
  104.     err = GetDirInfo( theSpec, &pb );
  105.         // Check there's no error and FSSpec is a directory
  106.     if ( noErr != err || ! ( pb.dirInfo.ioFlAttrib & ioDirMask ) )
  107.         return false;
  108.                                             // If folder is on a different
  109.     if ( ! AddVolume( theSpec->vRefNum ) )    // volume to the others increment.
  110.         return false;                        // Returns false if volume can't
  111.                                             // handle PBCatSearch().
  112.             
  113.     tempPtr = (WatchFolderPtr) NewPtr( sizeof( WatchFolderRec ) );
  114.     tempPtr->theSpec = *theSpec;
  115.     tempPtr->theDirID = pb.dirInfo.ioDrDirID;
  116.     tempPtr->theFileCount = pb.dirInfo.ioDrNmFls;
  117.     tempPtr->next = NULL;
  118.     
  119.     AddToList( (ItemPtr *)&gWatchFolderPtr, (ItemPtr)tempPtr );
  120.  
  121.     gNumberFolders++;
  122.     
  123.     return true;
  124. }
  125.  
  126.  
  127. // Check that the volume supports PBCatSearch(), if so create a
  128. // WatchVolumePtr and add to volume linked list.
  129.  
  130.  
  131. Boolean    AddVolume( short theVolRef )
  132. {
  133.     WatchVolumePtr            tempPtr;
  134.     GetVolParmsInfoBuffer    aBuffer;
  135.     OSErr                    err;
  136.         
  137.     if ( VolumeInList( theVolRef ) )
  138.         return true;
  139.  
  140.     err = GetVolInfo( theVolRef, &aBuffer );
  141.         // Check there's no error and FSSpec is a directory
  142.     if ( noErr != err || ! hasCatSearch( aBuffer ) )
  143.         return false;
  144.             
  145.     tempPtr = (WatchVolumePtr) NewPtr( sizeof( WatchVolumeRec ) );
  146.     tempPtr->theVolRef = theVolRef;
  147.     GetDateTime( &tempPtr->theLastModCheck );
  148.     tempPtr->next = NULL;
  149.     
  150.     AddToList( (ItemPtr *)&gWatchVolumePtr, (ItemPtr)tempPtr );
  151.  
  152.     gNumberVolumes++;
  153.     
  154.     return true;
  155. }
  156.  
  157.  
  158. // Just set up a parameter block for a PBHGetVolParms() call.
  159.  
  160. static OSErr    GetVolInfo( short theVolRef, GetVolParmsInfoBuffer* theBuffer )
  161. {
  162.     HParamBlockRec        pb;
  163.     OSErr                err;
  164.  
  165.     pb.ioParam.ioCompletion = NULL;
  166.     pb.ioParam.ioNamePtr = NULL;
  167.     pb.ioParam.ioVRefNum = theVolRef;
  168.     pb.ioParam.ioBuffer = (Ptr)theBuffer;
  169.     pb.ioParam.ioReqCount = sizeof( *theBuffer );
  170.  
  171.     err = PBHGetVolParms( &pb, false );        // Won't do this asynchronusly
  172.     
  173.     return err;
  174. }
  175.  
  176.  
  177. // Get directory information for an FSSpec.
  178.  
  179. OSErr    GetDirInfo( FSSpec* theSpec, CInfoPBRec* thePB)
  180. {
  181.     OSErr         err;
  182.  
  183.     thePB->dirInfo.ioNamePtr = theSpec->name;
  184.     thePB->dirInfo.ioVRefNum = theSpec->vRefNum;
  185.     thePB->dirInfo.ioDrDirID = theSpec->parID;
  186.     thePB->dirInfo.ioFDirIndex = 0;    // Use ioNamePtr and ioDirID
  187.     thePB->dirInfo.ioACUser = 0;    // If this does not compile try using 
  188.                                     // thePB->dirInfo.filler2 or thePB->dirInfo.ioACUser
  189.                                     // Clear it before calling PBGetCatInfo()
  190.     err = PBGetCatInfo( thePB, false );
  191.  
  192.     return err;
  193. }
  194.  
  195.  
  196. // Just add the item to the beginning of the linked list
  197.  
  198. static void        AddToList( ItemPtr* theHeadPtr, ItemPtr theItem )
  199. {
  200.     ItemPtr        tempPtr = *theHeadPtr;
  201.     
  202.     *theHeadPtr = theItem;
  203.     theItem->next = tempPtr;
  204. }
  205.  
  206. // Just keep gWatchFolderPtr referred to in this file. 
  207.  
  208. WatchFolderPtr    GetHeadFolderPtr( void )
  209. {
  210.     return gWatchFolderPtr;
  211. }
  212.  
  213. WatchVolumePtr    GetHeadVolumePtr( void )
  214. {
  215.     return gWatchVolumePtr;
  216. }
  217.  
  218. long    GetNumberOfVolumes( void )
  219. {
  220.     return gNumberVolumes;
  221. }
  222.  
  223. long    GetNumberOfFolders( void )
  224. {
  225.     return gNumberFolders;
  226. }
  227.  
  228. void    FirstVolumeToLast( void )
  229. {
  230.     FirstToLast( (ItemPtr *)&gWatchVolumePtr );
  231. }
  232.  
  233.  
  234. // Move the first item in the watch folder list to the end of the list.
  235. // Handles an empty or one item list.
  236.  
  237. static void    FirstToLast( ItemPtr* theHeadPtr )
  238. {
  239.     ItemPtr        tempPtr = *theHeadPtr;
  240.  
  241.         // If no items in list
  242.     if ( ! tempPtr )
  243.         return;
  244.     
  245.     while ( tempPtr->next )                // Go to the last item in the linked list
  246.         tempPtr = tempPtr->next;
  247.     
  248.     if ( tempPtr != *theHeadPtr )        // Would be equal if only one folder to watch
  249.     {                                    // - then the first is the last already.
  250.         tempPtr->next = *theHeadPtr;        // Add old head of list to end
  251.         tempPtr = *theHeadPtr;                // Keep so can NULL next
  252.         *theHeadPtr = (*theHeadPtr)->next;    // Head of list is now next in list
  253.         tempPtr->next = NULL;                // Now at end of list, so next is NULL
  254.     }
  255. }
  256.  
  257.  
  258. // Given an FSSpec, get the full path to the folder specified and add it to our
  259. // 'WFol' resources. It will then be loaded by InitWatchFolders() when launched.
  260.  
  261. void    AddFolderPathResource( FSSpec* theSpec )
  262. {
  263.     Str255    aPath;
  264.     Handle    aHandle;
  265.     
  266.     if ( noErr != GetFullPath( theSpec, aPath ) )
  267.         return;
  268.         
  269.     aHandle = (Handle)NewHandle( aPath[0] + 1 );
  270.     HLock( aHandle );
  271.     BlockMoveData( aPath, *aHandle, aPath[0] + 1 );
  272.     HUnlock( aHandle );
  273.     
  274.     AddResource( aHandle, kWatchFolderResource, Unique1ID( kWatchFolderResource ), theSpec->name );
  275.     ReleaseResource( aHandle );
  276. }
  277.  
  278.  
  279. // Check through linked list to see if a folder with this volume is already
  280. // there.
  281.  
  282. static WatchVolumePtr    VolumeInList( short theVolRef )
  283. {
  284.     WatchVolumePtr    tempPtr = GetHeadVolumePtr( );
  285.     
  286.     while ( tempPtr )
  287.     {
  288.         if ( theVolRef == tempPtr->theVolRef )
  289.             break;
  290.     
  291.         tempPtr = (WatchVolumePtr)tempPtr->next;
  292.     }
  293.     
  294.     return tempPtr;
  295. }
  296.  
  297.  
  298. // Check through linked list to see if this file spec is already there.
  299.  
  300. WatchFolderPtr    FolderInList( FSSpec* theSpec )
  301. {
  302.     WatchFolderPtr    tempPtr = GetHeadFolderPtr( );
  303.  
  304.     if ( ! theSpec )
  305.         return NULL;
  306.     
  307.     while ( tempPtr )
  308.     {
  309.         if ( theSpec->vRefNum == tempPtr->theSpec.vRefNum
  310.                 && theSpec->parID == tempPtr->theSpec.parID
  311.                     && EqualString( theSpec->name, tempPtr->theSpec.name, false, false ) )
  312.         {
  313.             break;
  314.         }
  315.     
  316.         tempPtr = (WatchFolderPtr)tempPtr->next;
  317.     }
  318.     
  319.     return tempPtr;
  320. }
  321.  
  322.  
  323. // Check through linked list to see if this volume and the directory
  324. // id are of a folder being watched.
  325.  
  326. Boolean    VolumeAndDirIDInList( short theVolRef, long theDirID )
  327. {
  328.     WatchFolderPtr    tempPtr = GetHeadFolderPtr( );
  329.     Boolean            result = false;
  330.     
  331.     while ( tempPtr )
  332.     {
  333.         if ( theVolRef == tempPtr->theSpec.vRefNum
  334.                 && theDirID == tempPtr->theDirID )
  335.         {
  336.             result = true;
  337.             break;
  338.         }
  339.     
  340.         tempPtr = (WatchFolderPtr)tempPtr->next;
  341.     }
  342.     
  343.     return result;
  344. }
  345.  
  346.  
  347. // Given an FSFSpec return the full path name for it.
  348.  
  349. static OSErr    GetFullPath( FSSpec* theSpec, StringPtr thePath )
  350. {
  351.     CInfoPBRec    pb;
  352.     Str255        dirName;
  353.     OSErr        err;
  354.     
  355.     thePath[0] = 0;        // Null the string
  356.     InsertAtBeginning( theSpec->name, thePath );
  357.     InsertAtBeginning( "\p:", thePath );    // Add the folder name
  358.     
  359.     pb.dirInfo.ioNamePtr = dirName;
  360.     pb.dirInfo.ioVRefNum = theSpec->vRefNum;
  361.     pb.dirInfo.ioDrParID = theSpec->parID;
  362.     pb.dirInfo.ioFDirIndex = -1;            // Get info about the directory
  363.     
  364.     do
  365.     {
  366.         pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
  367.         err = PBGetCatInfo( &pb, false);
  368.         if ( noErr != err ) goto done;
  369.             
  370.         InsertAtBeginning( dirName, thePath );
  371.         if ( pb.dirInfo.ioDrDirID != fsRtDirID )    // If it's not the disk name
  372.             InsertAtBeginning( "\p:", thePath );    // Then add a : ready for next directory
  373.         
  374.     } while ( pb.dirInfo.ioDrDirID != fsRtDirID );
  375.  
  376. done:    
  377.     return err;
  378. }
  379.  
  380.  
  381. // Simply inserts the pascal source string at the beginning of the
  382. // destination pascal string.
  383.  
  384. static void    InsertAtBeginning( StringPtr sourceStr, StringPtr destStr )
  385. {
  386.     BlockMoveData( (void *)&destStr[1], (void *)( &destStr[1] + sourceStr[0] ), destStr[0] );
  387.     BlockMoveData( (void *)&sourceStr[1], (void *)&destStr[1], sourceStr[0] );
  388.     destStr[0] += sourceStr[0];
  389. }
  390.